package com.star.rpc.proxy;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.star.rpc.RpcApplication;
import com.star.rpc.config.RpcConfig;
import com.star.rpc.constant.RpcConstant;
import com.star.rpc.fault.retry.RetryStrategy;
import com.star.rpc.fault.retry.RetryStrategyFactory;
import com.star.rpc.fault.tolerant.TolerantStrategy;
import com.star.rpc.fault.tolerant.TolerantStrategyFactory;
import com.star.rpc.loadbalancer.LoadBalancer;
import com.star.rpc.loadbalancer.LoadBalancerFactory;
import com.star.rpc.modal.RpcRequest;
import com.star.rpc.modal.RpcResponse;
import com.star.rpc.modal.ServiceMetaInfo;
import com.star.rpc.registry.Registry;
import com.star.rpc.registry.RegistryFactory;
import com.star.rpc.serializer.Serializer;
import com.star.rpc.server.tcp.VertxTcpClient;
import com.star.rpc.spi.SerializerFactory;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * packageName com.star.example.consumer
 *
 * @author zerostart
 * @className ServiceProxy
 * @date 2024/11/18
 * @description
 */
@Slf4j
public class ServiceProxy implements InvocationHandler {

    public Object invoke1(Object proxy, Method method, Object[] args) throws Throwable {
        // 指定序列化器
        final Serializer serializer = SerializerFactory.getInstance(RpcApplication.getRpcConfig().getSerializer());

        String serviceName = method.getDeclaringClass().getName();
        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .args(args)
                .parameterTypes(method.getParameterTypes())
                .build();


        try {
            byte[] bodyBytes = serializer.serialize(rpcRequest);

            //从注册中心获取服务提供者的地址
            RpcConfig rpcConfig = RpcApplication.getRpcConfig();
            // 根据服务中心的类别，获取 服务
            Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());

            ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
            serviceMetaInfo.setServiceName(serviceName);
            serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);

            List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
            if (CollUtil.isEmpty(serviceMetaInfoList)) {
                throw new RuntimeException("暂无服务地址");
            }

            ServiceMetaInfo selectdServiceMetaInfo = serviceMetaInfoList.get(0);


            // 发送请求
            try (HttpResponse httpResponse = HttpRequest.post(selectdServiceMetaInfo.getServiceAddress())
                    .body(bodyBytes)
                    .execute()) {
                byte[] result = httpResponse.bodyBytes();

                // 反序列化
                RpcResponse rpcResponse = serializer.deserialize(result, RpcResponse.class);
                return rpcResponse.getData();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 构造请求
        String serviceName = method.getDeclaringClass().getName();

        RpcRequest rpcRequest = RpcRequest.builder()
                .serviceName(serviceName)
                .methodName(method.getName())
                .parameterTypes(method.getParameterTypes())
                .args(args)
                .build();


        // 序列化
        // 从注册中心获取服务请求者地址
        RpcConfig rpcConfig = RpcApplication.getRpcConfig();
        Registry registry = RegistryFactory.getInstance(rpcConfig.getRegistryConfig().getRegistry());

        ServiceMetaInfo serviceMetaInfo = new ServiceMetaInfo();
        serviceMetaInfo.setServiceName(serviceName);
        serviceMetaInfo.setServiceVersion(RpcConstant.DEFAULT_SERVICE_VERSION);

        log.info("服务名{}", serviceMetaInfo.getServiceKey());
        List<ServiceMetaInfo> serviceMetaInfoList = registry.serviceDiscovery(serviceMetaInfo.getServiceKey());
        if (CollUtil.isEmpty(serviceMetaInfoList)) {
            throw new RuntimeException("暂无服务地址");
        }
        // 负载均衡

        LoadBalancer loadBalancer = LoadBalancerFactory.getLoadBalancer(rpcConfig.getLoadBalancer());
        //
        Map<String, Object> requestParams = new HashMap<>();
        requestParams.put("methodName", rpcRequest.getMethodName());
        ServiceMetaInfo selectedServiceMetaInfo = loadBalancer.select(requestParams, serviceMetaInfoList);

        RpcResponse rpcResponse = null;

        try {
            // 使用重试机制
            RetryStrategy retryStrategy = RetryStrategyFactory.getInstance(rpcConfig.getRetryStrategy());
            rpcResponse = retryStrategy.doRetry(() ->
                    VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo)
            );
        } catch (Exception e) {
            TolerantStrategy tolerantStrategy = TolerantStrategyFactory.getInstance(rpcConfig.getTolerantStrategy());
            tolerantStrategy.doTolerant(null, e);
        }


        //RpcResponse rpcResponse = VertxTcpClient.doRequest(rpcRequest, selectedServiceMetaInfo);
//            // 发送TCP请求
//            Vertx vertx = Vertx.vertx();
//            NetClient netClient = vertx.createNetClient();
//
//            CompletableFuture<RpcResponse> responseFuture = new CompletableFuture<>();
//            netClient.connect(selectedServiceMetaInfo.getServicePort(), selectedServiceMetaInfo.getServiceHost(), result -> {
//                if (result.succeeded()) {
//
//
//                    System.out.println("connected to TcpServer");
//                    NetSocket socket = result.result();
//                    // 发送数据
//                    // 构造消息
//                    ProtocolMessage<RpcRequest> protocolMessage = new ProtocolMessage<>();
//                    ProtocolMessage.Header header = new ProtocolMessage.Header();
//                    // 设置header
//                    header.setMagic(ProtocolConstant.PROTOCOL_MAGIC);
//                    header.setVersion(ProtocolConstant.PROTOCOL_VERSION);
//                    header.setSerializer((byte) ProtocolMessageSerializerEnum.getEnumByValue(RpcApplication.getRpcConfig().getSerializer()).getKey());
//                    header.setType((byte) ProtocolMessageTypeEnum.REQUEST.getKey());
//                    header.setRequestId(IdUtil.getSnowflakeNextId());
//                    protocolMessage.setHeader(header);
//                    protocolMessage.setBody(rpcRequest);
//
//                    // 编码 请求
//                    try {
//                        Buffer endcodeBuffer = ProtocolMessageEncoder.encode(protocolMessage);
//                        socket.write(endcodeBuffer);
//                    } catch (Exception e) {
//                        throw new RuntimeException("协议消息编码错误");
//                    }
//
//                    // 接收响应
//                    socket.handler(buffer -> {
//                        try {
//                            ProtocolMessage<RpcResponse> rpcResponseProtocolMessage = (ProtocolMessage<RpcResponse>) ProtocolMessageDecoder.decode(buffer);
//                            // 手动完成，将
//                            responseFuture.complete(rpcResponseProtocolMessage.getBody());
//                        } catch (Exception e) {
//                            throw new RuntimeException("协议消息解码错误");
//                        }
//                    });
//
//                } else {
//                    System.err.println("failed to connect to TcpServer");
//                }
//            });
//            RpcResponse rpcResponse = responseFuture.get();
//            // 关闭连接
//            netClient.close();
        log.info("调用结果-----{}", rpcResponse.getData());
        return rpcResponse.getData();

    }
}
